package org.onion.pattern.event.spring.signal;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
@Slf4j
public class EventPublishedHandler {

    @Autowired
    private ApplicationContext applicationContext;

//    private final static MessageQueueSelector messageQueueSelector = new SelectMessageQueueByHash();
//    private final        DefaultMQProducer    producer;
//    private final        ThreadPoolExecutor   executor;

//    private final String publishableMessageNotifierTopic;
//    private List<IPublishableEventContextCustomizer> publishContextCustomizers = new ArrayList<>();

//    public List<IPublishableEventContextCustomizer> getPublishContextCustomizers() {
//        return publishContextCustomizers;
//    }
//
//    public void setPublishContextCustomizers(
//            List<IPublishableEventContextCustomizer> publishContextCustomizers) {
//        this.publishContextCustomizers = publishContextCustomizers;
//    }

//    public ExternalEventSignalHandler(
//            String publishableMessageNotifierTopic, DefaultMQProducer producer) {
//        this.publishableMessageNotifierTopic = publishableMessageNotifierTopic;
//        this.producer = producer;
//        this.executor =
//                new ThreadPoolExecutor(
//                        1,
//                        1,
//                        1000 * 60,
//                        TimeUnit.MILLISECONDS,
//                        new LinkedBlockingQueue<>(1),
//                        new ThreadFactoryImpl("EventPublishableNotifierThread_"),
//                        new ThreadPoolExecutor.DiscardPolicy());
//    }

    @Pointcut(
            "@annotation(org.onion.pattern.event.spring.signal.EventPublished) || @within(org.onion.pattern.event.spring.signal.EventPublished)")
    public void EventPublishSignalAspect() {
    }

    private EventPublished findAnnotation(JoinPoint joinPoint) {
        if (joinPoint instanceof MethodInvocationProceedingJoinPoint) {
            MethodInvocationProceedingJoinPoint proceedingJoinPoint = (MethodInvocationProceedingJoinPoint) joinPoint;

            MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
            Method method = methodSignature.getMethod();
            EventPublished annotation = method.getAnnotation(EventPublished.class);
            if (annotation != null) {
                return annotation;
            }
        }
        return AnnotationUtils.findAnnotation(joinPoint.getSignature().getDeclaringType(), EventPublished.class);
    }

    @After("EventPublishSignalAspect()")
    public void after(JoinPoint joinPoint) {
        EventPublished annotation = null;
        try {
            annotation = findAnnotation(joinPoint);
        } catch (Exception e) {
            log.warn("", e);
        }
        String group = "";
        if (annotation != null) {
            group = annotation.value();
        }

        EventPublishedEvent event = new EventPublishedEvent(group);
        //todo 异步处理...
        this.applicationContext.publishEvent(event);
    }

}
